package com.example.zhang.util;

import com.example.zhang.mapper.CabinetMapper;
import com.fazecast.jSerialComm.SerialPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;

public class SerialPortUtil {
    private static SerialPort serialPort;
    private static InputStream inputStream;
    private static OutputStream outputStream;

    // 串口参数
    private static final String PORT_DESCRIPTOR = "COM6"; // 根据实际情况修改
    private static final int BAUD_RATE = 38400;

    /**
     * 初始化串口
     */
    public static void init() {
        serialPort = SerialPort.getCommPort(PORT_DESCRIPTOR);
        serialPort.setComPortParameters(BAUD_RATE, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
        serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 1000);
        if (serialPort.openPort()) {
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();
            System.out.println("串口打开成功: " + PORT_DESCRIPTOR);
        } else {
            throw new RuntimeException("串口打开失败: " + PORT_DESCRIPTOR);
        }
    }

    /**
     * 关闭串口
     */
    public static void close() {
        try {
            if (inputStream != null) inputStream.close();
            if (outputStream != null) outputStream.close();
        } catch (IOException ignored) {}
        if (serialPort != null && serialPort.isOpen()) {
            serialPort.closePort();
        }
    }

    /**
     * 发送数据
     */
    public static synchronized void send(byte[] data) throws IOException {
        if (outputStream != null) {
            outputStream.write(data);
            outputStream.flush();
        }
    }

    /**
     * 接收数据（阻塞读取指定长度）
     */
    public static synchronized byte[] receive(int length) throws IOException {
        byte[] buffer = new byte[length];
        int read = 0;
        while (read < length) {
            int r = inputStream.read(buffer, read, length - read);
            if (r == -1) break;
            read += r;
        }
        return Arrays.copyOf(buffer, read);
    }

    /**
     * 非阻塞读取（读取可用字节）
     */
    public static synchronized byte[] readAvailable() throws IOException {
        int available = inputStream.available();
        if (available > 0) {
            byte[] buffer = new byte[available];
            inputStream.read(buffer);
            return buffer;
        }
        return new byte[0];
    }

    /**
     * 查询终端最新状态并同步到数据库
     */
    public static Map<String, Object> queryAndUpdateDb(CabinetMapper mapper) {
        try {
            byte[] queryFrame = ProtocolUtil.buildQueryFrame((byte)0x01, (byte)0x01);
            send(queryFrame);
            Thread.sleep(300);
            byte[] resp = readAvailable();
            if (resp == null || resp.length < 10) {
                return null;
            }
            // 多帧分割与解析
            java.util.List<java.util.Map<String, Object>> parsedList = StatusFrameParser.parseFrames(resp);
            java.util.Map<String, Object> lastValid = null;
            for (java.util.Map<String, Object> parsed : parsedList) {
                if (parsed.containsKey("error")) continue;
                // 同步到数据库
                if(parsed.get("currentTemp") != null) {
                    mapper.updateCurrentTemperature((Double)parsed.get("currentTemp"));
                }
                if(parsed.get("setTemp") != null) {
                    mapper.updateSetTemp((Double)parsed.get("setTemp"));
                }
                if(parsed.get("compressorStatus") != null) {
                    mapper.updateCompressorStatus((Integer)parsed.get("compressorStatus"));
                }
                if(parsed.get("lockStates") != null) {
                    @SuppressWarnings("unchecked")
                    java.util.List<Integer> drawers = (java.util.List<Integer>)parsed.get("lockStates");
                    if (drawers.size() > 10) drawers = drawers.subList(0, 10);
                    String json = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(drawers);
                    mapper.updateDrawerStatus(json);
                }
                lastValid = parsed;
            }
            return lastValid;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 查询终端最新状态并同步到数据库，失败自动重试3次
     */
    public static Map<String, Object> queryAndUpdateDbWithRetry(CabinetMapper mapper) {
        for (int i = 0; i < 3; i++) {
            Map<String, Object> result = queryAndUpdateDb(mapper);
            if (result != null) return result;
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        return null;
    }

    /**
     * 发送开锁指令
     */
    public static void sendUnlockCommand(int drawerId) {
        try {
            int drawerIndex = drawerId - 1;
            if (drawerIndex < 0 || drawerIndex >= 10) return;
            int controlBits = 1 << drawerIndex;
            byte[] unlockFrame = ProtocolUtil.buildUnlockFrame((byte)0x01, (byte)0x01, controlBits);
            send(unlockFrame);
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送设定温度指令
     */
    public static void sendSetTempCommand(double value) {
        try {
            byte tempByte = buildTempByte(value);
            byte[] setTempFrame = ProtocolUtil.buildSetTempFrame((byte)0x01, (byte)0x01, tempByte);
            send(setTempFrame);
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送压缩机控制指令
     */
    public static void sendCompressorCommand(int status) {
        try {
            byte action = (byte)(status > 0 ? 1 : 0);
            byte[] controlFrame = ProtocolUtil.buildCompressorControlFrame((byte)0x01, (byte)0x01, action);
            send(controlFrame);
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 辅助：将温度值转为协议字节
    public static byte buildTempByte(double value) {
        boolean negative = value < 0;
        double abs = Math.abs(value);
        int intPart = (int) abs;
        int frac = (abs - intPart) >= 0.5 ? 1 : 0;
        int temp = (negative ? 0x80 : 0x00) | ((intPart & 0x3F) << 1) | frac;
        return (byte) temp;
    }

    
} 